Skip to content

Comments

미션 목록 버그 수정#395

Merged
HA-SEUNG-JEONG merged 6 commits intodevelopfrom
fix/mission-list
Feb 18, 2026
Merged

미션 목록 버그 수정#395
HA-SEUNG-JEONG merged 6 commits intodevelopfrom
fix/mission-list

Conversation

@HA-SEUNG-JEONG
Copy link
Contributor

@HA-SEUNG-JEONG HA-SEUNG-JEONG commented Feb 18, 2026

🌱 연관된 이슈

리더가 아닌 경우 종료된 스터디 내 미션 목록에서 미션 상세로 접근이 불가능

☘️ 작업 내용

mission-card.tsx에서 비리더인 경우 status === 'ENDED' 인 조건 추가

🍀 참고사항

스크린샷 (선택)

Summary by CodeRabbit

릴리스 노트

  • 버그 수정

    • 토큰 갱신 실패 시 알림 대신 로그인 페이지로 자동 이동
    • 인증 정보가 없을 때 불필요한 토큰 갱신 시도 방지
    • 클립보드 복사 피드백을 알림에서 토스트 알림으로 개선
  • 새로운 기능

    • 종료된 미션을 클릭 가능하도록 개선
    • 모집 마감 여부를 확인하여 신청 버튼 상태 관리 개선

@vercel
Copy link

vercel bot commented Feb 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
study-platform-client-dev Ready Ready Preview, Comment Feb 18, 2026 6:33am

@HA-SEUNG-JEONG HA-SEUNG-JEONG changed the title Fix/mission list 미션 목록 버그 수정 Feb 18, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

인증 토큰 처리 로직을 강화하여 인증 정보 없을 시 토큰 리프레시 시도를 방지하고, alert를 로그인 리다이렉트로 변경했습니다. 또한 미션 카드의 클릭 가능 상태에 ENDED를 추가하고, 모집 마감일 기반으로 지원 버튼을 비활성화하는 UI 로직을 추가했습니다.

Changes

Cohort / File(s) Summary
인증 토큰 처리 강화
src/api/client/axios.ts, src/api/client/axiosV2.ts
hasAuthToken 헬퍼 함수 추가로 AUTH001 에러 발생 시 인증 정보 존재 여부를 확인한 후에만 토큰 리프레시 시도. 토큰 리프레시 실패 시 alert 대신 /login으로 리다이렉트하도록 변경. 일반 및 멀티파트 axios 인스턴스 모두에 적용.
카드 상호작용 개선
src/components/card/mission-card.tsx
isCardClickable 로직 수정으로 비리더 사용자가 ENDED 상태의 미션 카드도 클릭 가능하도록 확장.
모집 마감일 기반 UI 업데이트
src/components/summary/study-info-summary.tsx
dayjs를 사용한 isDeadlinePassed 계산 추가. 마감일 경과 시 지원 버튼 비활성화 및 "모집 마감" 텍스트 표시. alert 대신 toast 알림으로 변경.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 인증은 먼저 확인하고
마감일도 놓치지 않으며
카드는 쭈욱 눌러도 좋고
토스트로 속삭여주네요
로그인 가는 길 밝혀주니
모두 함께 춤을 춘답니다! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning PR 제목은 '미션 목록 버그 수정'이지만, 실제 변경사항은 단순 버그 수정을 넘어 여러 파일의 다양한 기능 개선(토큰 갱신 로직, 로그인 리다이렉트, 토스트 알림, 마감일 처리 등)을 포함하고 있습니다. PR 제목을 더 정확하게 변경하여 실제 변경사항을 반영하도록 권장합니다. 예: '인증 및 미션 UI 개선 사항' 또는 구체적인 변경사항을 명시하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/mission-list

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/api/client/axiosV2.ts (1)

197-211: ⚠️ Potential issue | 🟠 Major

axios.ts와 동일한 버그: multipart 인터셉터에서 axiosInstanceV2를 사용하여 재시도합니다.

Line 206과 225에서 axiosInstanceForMultipartV2 대신 axiosInstanceV2를 사용하고 있습니다. 토큰 갱신 후 multipart 요청이 잘못된 Content-Type으로 재시도됩니다.

🐛 수정 제안
              if (originalRequest) {
                originalRequest.headers.Authorization = `Bearer ${token}`;

-                return axiosInstanceV2(originalRequest);
+                return axiosInstanceForMultipartV2(originalRequest);
              }

Line 225도 동일하게 수정:

              if (originalRequest) {
                originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;

-                return axiosInstanceV2(originalRequest);
+                return axiosInstanceForMultipartV2(originalRequest);
              }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api/client/axiosV2.ts` around lines 197 - 211, The multipart
interceptor's retry path is using axiosInstanceV2 which causes retried multipart
requests to lose the multipart Content-Type; in the isRefreshing branch where
failedQueue resolves and in the retry call (currently invoking
axiosInstanceV2(originalRequest)), change those retries to use
axiosInstanceForMultipartV2 so multipart requests are retried with the proper
instance and headers; locate the logic around isRefreshing, failedQueue,
originalRequest and replace axiosInstanceV2 with axiosInstanceForMultipartV2 in
that multipart interceptor.
src/api/client/axios.ts (1)

197-211: ⚠️ Potential issue | 🟠 Major

Multipart 인터셉터에서 재시도 시 JSON 인스턴스(axiosInstance)를 사용하고 있습니다.

Line 206과 225에서 axiosInstanceForMultipart 대신 axiosInstance를 사용하여 재시도하고 있습니다. 토큰 갱신 후 multipart 요청이 JSON Content-Type 헤더로 재시도되어 서버에서 실패할 수 있습니다.

수정 사항
// Line 206 (isRefreshing 대기열 처리)
              if (originalRequest) {
                originalRequest.headers.Authorization = `Bearer ${token}`;

-                return axiosInstance(originalRequest);
+                return axiosInstanceForMultipart(originalRequest);
              }
// Line 225 (토큰 갱신 후 재시도)
              if (originalRequest) {
                originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;

-                return axiosInstance(originalRequest);
+                return axiosInstanceForMultipart(originalRequest);
              }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api/client/axios.ts` around lines 197 - 211, The multipart interceptor is
retrying requests using axiosInstance instead of the multipart-specific
axiosInstanceForMultipart, causing retried requests to use JSON headers; modify
the retry logic inside the isRefreshing branch (where failedQueue is pushed and
in the then handler that sets originalRequest.headers.Authorization and calls
axiosInstance(originalRequest)) to call
axiosInstanceForMultipart(originalRequest) when the originalRequest corresponds
to a multipart request (i.e., came from the multipart interceptor), ensuring the
correct Content-Type and instance are used; preserve the same promise handling
for failedQueue resolution/rejection and update any places that enqueue or
resolve with the token to consistently use axiosInstanceForMultipart for
multipart originalRequest objects.
🧹 Nitpick comments (3)
src/api/client/axios.ts (2)

62-66: refreshAccessToken 실패 시 중복 리다이렉트 가능성.

refreshAccessToken 내부(line 63)와 호출부(line 155, 161)에서 모두 window.location.href = '/login'을 실행합니다. refreshAccessToken이 실패하면 내부에서 먼저 리다이렉트한 후 null을 반환하고, 호출부에서도 다시 리다이렉트합니다. 브라우저에서 실질적 문제는 없지만, refreshAccessToken에서 리다이렉트를 제거하고 호출부에서만 처리하는 것이 책임 분리 측면에서 더 깔끔합니다.

♻️ 제안: refreshAccessToken에서 리다이렉트 제거
   } catch {
-    window.location.href = '/login';
-
     return null;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api/client/axios.ts` around lines 62 - 66, The refreshAccessToken
function currently performs a window.location.href = '/login' in its catch block
and also returns null, causing duplicate redirects when callers (the places that
call refreshAccessToken and then check for null at the call sites that currently
also set window.location.href = '/login') handle the failure; remove the
redirect from the catch in refreshAccessToken so it only returns null on
failure, leaving the responsibility of redirecting to the callers that already
perform window.location.href = '/login' after receiving null (update the catch
in refreshAccessToken and verify the calling sites that check its return value
still perform the redirect).

104-175: JSON 인터셉터와 multipart 인터셉터가 거의 동일한 코드를 중복하고 있습니다.

두 인터셉터의 응답 에러 핸들링 로직이 재시도 인스턴스만 다르고 나머지는 완전히 동일합니다. 공통 로직을 팩토리 함수로 추출하면 유지보수성이 크게 향상됩니다. 위에서 지적한 multipart 인스턴스 버그도 이러한 중복에서 비롯된 것입니다.

♻️ 팩토리 함수 추출 제안
+const createResponseErrorInterceptor = (instance: typeof axiosInstance) => {
+  return async (error: unknown) => {
+    if (
+      isAxiosError(error) &&
+      error.response &&
+      isApiError(error.response.data)
+    ) {
+      const errorResponseBody = error.response.data;
+      const originalRequest = error.config;
+
+      if (errorResponseBody.errorCode === 'AUTH001') {
+        if (!hasAuthToken(originalRequest)) {
+          return Promise.reject(new ApiError(errorResponseBody));
+        }
+        // ... shared refresh logic using `instance` for retries
+      }
+      return Promise.reject(new ApiError(errorResponseBody));
+    }
+    return Promise.reject(error);
+  };
+};
+
-axiosInstance.interceptors.response.use((config) => config, async (error) => { ... });
-axiosInstanceForMultipart.interceptors.response.use((config) => config, async (error) => { ... });
+axiosInstance.interceptors.response.use((config) => config, createResponseErrorInterceptor(axiosInstance));
+axiosInstanceForMultipart.interceptors.response.use((config) => config, createResponseErrorInterceptor(axiosInstanceForMultipart));

Also applies to: 178-248

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api/client/axios.ts` around lines 104 - 175, The response-error handling
logic in the axiosInstance interceptor (symbols: axiosInstance, isAxiosError,
isApiError, ApiError, refreshAccessToken, isRefreshing, failedQueue,
processFailedQueue, hasAuthToken, originalRequest) is duplicated for the
multipart instance; extract that logic into a reusable factory function (e.g.,
createResponseErrorInterceptor(retryInstance)) that accepts the retry axios
instance to use for replaying original requests, implements the AUTH001
token-refresh flow including queueing via failedQueue/processFailedQueue and
hasAuthToken checks, and returns the error handler to register with both
axiosInstance and the multipart instance so both reuse the same implementation
and avoid the multipart bug.
src/api/client/axiosV2.ts (1)

90-102: hasAuthTokenaxios.tsaxiosV2.ts에 동일하게 중복 정의되어 있습니다.

두 파일에서 완전히 동일한 구현을 사용하고 있으므로, 공통 유틸리티(예: src/api/client/auth-utils.ts)로 추출하여 import하는 것을 권장합니다. 단, V2 전환이 완료되면 axios.ts 자체가 제거될 예정이라면 현 상태로 유지해도 괜찮습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api/client/axiosV2.ts` around lines 90 - 102, The hasAuthToken function
is duplicated across axios.ts and axiosV2.ts; extract it into a shared utility
(e.g., auth-utils) and import it from both modules: move the implementation that
uses getCookie('accessToken') and inspects requestConfig?.headers?.Authorization
(handling array and string forms) into a new exported function named
hasAuthToken in the shared auth-utils module, replace the inline definitions in
both files with imports of that function, and keep the same signature (accepting
an InternalAxiosRequestConfig-like param) to avoid breaking call sites.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/card/mission-card.tsx`:
- Around line 90-96: Update the outdated inline comments near the
isCardClickable logic: change the comment that currently says "비리더: 진행중/평가완료" to
"비리더: 진행중/제출마감/평가완료" and change the comment that currently says "비리더: 진행예정/제출마감"
to "비리더: 진행예정" so they reflect the new branch behavior in isCardClickable (the
non-leader branch now includes ENDED as clickable); locate comments adjacent to
the isCardClickable function and replace the two phrases accordingly.

---

Outside diff comments:
In `@src/api/client/axios.ts`:
- Around line 197-211: The multipart interceptor is retrying requests using
axiosInstance instead of the multipart-specific axiosInstanceForMultipart,
causing retried requests to use JSON headers; modify the retry logic inside the
isRefreshing branch (where failedQueue is pushed and in the then handler that
sets originalRequest.headers.Authorization and calls
axiosInstance(originalRequest)) to call
axiosInstanceForMultipart(originalRequest) when the originalRequest corresponds
to a multipart request (i.e., came from the multipart interceptor), ensuring the
correct Content-Type and instance are used; preserve the same promise handling
for failedQueue resolution/rejection and update any places that enqueue or
resolve with the token to consistently use axiosInstanceForMultipart for
multipart originalRequest objects.

In `@src/api/client/axiosV2.ts`:
- Around line 197-211: The multipart interceptor's retry path is using
axiosInstanceV2 which causes retried multipart requests to lose the multipart
Content-Type; in the isRefreshing branch where failedQueue resolves and in the
retry call (currently invoking axiosInstanceV2(originalRequest)), change those
retries to use axiosInstanceForMultipartV2 so multipart requests are retried
with the proper instance and headers; locate the logic around isRefreshing,
failedQueue, originalRequest and replace axiosInstanceV2 with
axiosInstanceForMultipartV2 in that multipart interceptor.

---

Duplicate comments:
In `@src/api/client/axiosV2.ts`:
- Around line 104-175: This file duplicates the JSON/multipart axios interceptor
logic found in axios.ts; refactor by extracting the shared retry-on-AUTH001
interceptor into a reusable factory (e.g., createAuthRefreshInterceptor) and
apply it to axiosInstanceV2 via axiosInstanceV2.interceptors.response.use by
reusing the same implementation used for axios.ts; specifically move the logic
that checks isAxiosError, error.response, isApiError, AUTH001 handling
(references: axiosInstanceV2.interceptors.response.use, isRefreshing,
failedQueue, processFailedQueue, refreshAccessToken, hasAuthToken, ApiError,
originalRequest) into the factory so both axios.ts and axiosV2.ts can call it
and eliminate the duplicated code paths (ensure the factory returns the success
and failure handlers and preserves token queueing and redirect behavior).
- Around line 62-66: The refreshAccessToken function currently performs a
window.location.href redirect inside its catch block, duplicating redirect logic
already handled by the caller; remove the redirect from refreshAccessToken (keep
returning null or throwing as before) so that only the caller (the interceptor
or code that invokes refreshAccessToken) is responsible for navigating to
'/login'; update refreshAccessToken's catch to log/propagate the error and
return null, and ensure callers check for null and perform the single redirect
there (reference: refreshAccessToken and the axios V2 request/response
interceptor that invokes it).

---

Nitpick comments:
In `@src/api/client/axios.ts`:
- Around line 62-66: The refreshAccessToken function currently performs a
window.location.href = '/login' in its catch block and also returns null,
causing duplicate redirects when callers (the places that call
refreshAccessToken and then check for null at the call sites that currently also
set window.location.href = '/login') handle the failure; remove the redirect
from the catch in refreshAccessToken so it only returns null on failure, leaving
the responsibility of redirecting to the callers that already perform
window.location.href = '/login' after receiving null (update the catch in
refreshAccessToken and verify the calling sites that check its return value
still perform the redirect).
- Around line 104-175: The response-error handling logic in the axiosInstance
interceptor (symbols: axiosInstance, isAxiosError, isApiError, ApiError,
refreshAccessToken, isRefreshing, failedQueue, processFailedQueue, hasAuthToken,
originalRequest) is duplicated for the multipart instance; extract that logic
into a reusable factory function (e.g.,
createResponseErrorInterceptor(retryInstance)) that accepts the retry axios
instance to use for replaying original requests, implements the AUTH001
token-refresh flow including queueing via failedQueue/processFailedQueue and
hasAuthToken checks, and returns the error handler to register with both
axiosInstance and the multipart instance so both reuse the same implementation
and avoid the multipart bug.

In `@src/api/client/axiosV2.ts`:
- Around line 90-102: The hasAuthToken function is duplicated across axios.ts
and axiosV2.ts; extract it into a shared utility (e.g., auth-utils) and import
it from both modules: move the implementation that uses getCookie('accessToken')
and inspects requestConfig?.headers?.Authorization (handling array and string
forms) into a new exported function named hasAuthToken in the shared auth-utils
module, replace the inline definitions in both files with imports of that
function, and keep the same signature (accepting an
InternalAxiosRequestConfig-like param) to avoid breaking call sites.

@HA-SEUNG-JEONG HA-SEUNG-JEONG merged commit b51190e into develop Feb 18, 2026
18 checks passed
@HA-SEUNG-JEONG HA-SEUNG-JEONG deleted the fix/mission-list branch February 18, 2026 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants